From 03bbc8cec68eab2973ae491f44bab08dd039f939 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Mon, 12 Dec 2005 16:43:48 +0000 Subject: [PATCH] Added a hosts-allow facility to TCP connections, which allows us to restrict the acceptable connections based upon a regular expression comparison with the FQDN or the IP address. Use the hosts-allow facility to restrict access to the relocation socket. This adds the configuration option xend-relocation-hosts-allow, which takes a space-separated sequence of regular expressions. Pass the protocol class instance through to SocketServerConnection, rather than a new instance of that class. This means that the new instance need not be passed through SocketListener.acceptConnection. Make the SocketServerConnection and SocketListener classes start their corresponding threads and open their sockets (in the case of SocketListener) automatically. This means that callers do not need to save an instance locally, just to call run() or listen() on it. This also means that listenTCP and listenUnix can go -- simply creating a TCPListener or UnixListener instance is sufficient. Signed-off-by: Ewan Mellor --- tools/python/xen/web/connection.py | 61 +++++++++--------------- tools/python/xen/web/tcp.py | 41 +++++++++++----- tools/python/xen/web/unix.py | 19 ++++---- tools/python/xen/xend/XendRoot.py | 6 +++ tools/python/xen/xend/server/relocate.py | 13 ++++- 5 files changed, 77 insertions(+), 63 deletions(-) diff --git a/tools/python/xen/web/connection.py b/tools/python/xen/web/connection.py index 342e6a6f59..cc3660d538 100644 --- a/tools/python/xen/web/connection.py +++ b/tools/python/xen/web/connection.py @@ -19,7 +19,6 @@ import sys import threading -import select import socket import fcntl @@ -31,21 +30,17 @@ for TCP and unix-domain sockets (see tcp.py and unix.py). """ BUFFER_SIZE = 1024 +BACKLOG = 5 class SocketServerConnection: """An accepted connection to a server. """ - def __init__(self, sock, protocol, addr, server): + def __init__(self, sock, protocol_class): self.sock = sock - self.protocol = protocol - self.addr = addr - self.server = server + self.protocol = protocol_class() self.protocol.setTransport(self) - - - def run(self): threading.Thread(target=self.main).start() @@ -68,6 +63,10 @@ class SocketServerConnection: pass + def close(self): + self.sock.close() + + def write(self, data): self.sock.send(data) @@ -77,52 +76,38 @@ class SocketListener: Accepts connections and runs a thread for each one. """ - def __init__(self, protocol_class, backlog=None): - if backlog is None: - backlog = 5 + def __init__(self, protocol_class, hosts_allow = ''): self.protocol_class = protocol_class - self.sock = None - self.backlog = backlog - self.thread = None + self.sock = self.createSocket() + threading.Thread(target=self.main).start() - def createSocket(self): - raise NotImplementedError() + def close(self): + try: + self.sock.close() + except: + pass - def setCloExec(self): - fcntl.fcntl(self.sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) + def createSocket(self): + raise NotImplementedError() def acceptConnection(self, sock, protocol, addr): - return SocketServerConnection(sock, protocol, addr, self) - - - def listen(self): - if self.sock or self.thread: - raise IOError("already listening") - self.sock = self.createSocket() - self.sock.listen(self.backlog) - self.run() - - - def run(self): - self.thread = threading.Thread(target=self.main) - self.thread.start() + raise NotImplementedError() def main(self): try: + fcntl.fcntl(self.sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) + self.sock.listen(BACKLOG) + while True: try: (sock, addr) = self.sock.accept() - self.acceptConnection(sock, self.protocol_class(), - addr).run() + self.acceptConnection(sock, addr) except socket.error, ex: if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR): break finally: - try: - self.sock.close() - except: - pass + self.close() diff --git a/tools/python/xen/web/tcp.py b/tools/python/xen/web/tcp.py index f3d67a7de4..552bf4a5cc 100644 --- a/tools/python/xen/web/tcp.py +++ b/tools/python/xen/web/tcp.py @@ -17,20 +17,25 @@ #============================================================================ +import errno +import re import socket import time -import errno -from connection import * +import connection + +from xen.xend.XendLogging import log -class TCPListener(SocketListener): +class TCPListener(connection.SocketListener): - def __init__(self, port, protocol, backlog=None, interface=''): - SocketListener.__init__(self, protocol, backlog=backlog) + def __init__(self, protocol_class, port, interface, hosts_allow): self.port = port self.interface = interface - + self.hosts_allow = hosts_allow + connection.SocketListener.__init__(self, protocol_class) + + def createSocket(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -49,11 +54,23 @@ class TCPListener(SocketListener): else: raise - def acceptConnection(self, sock, protocol, addr): - return SocketServerConnection(sock, protocol, addr, self) + def acceptConnection(self, sock, addrport): + addr = addrport[0] + if self.hosts_allow is None: + connection.SocketServerConnection(sock, self.protocol_class) + else: + fqdn = socket.getfqdn(addr) + for h in self.hosts_allow: + if h.match(fqdn) or h.match(addr): + log.debug("Match %s %s", fqdn, h.pattern) + connection.SocketServerConnection(sock, + self.protocol_class) + return -def listenTCP(port, protocol, interface='', backlog=None): - l = TCPListener(port, protocol, interface=interface, backlog=backlog) - l.listen() - l.setCloExec() + try: + log.warn("Rejected connection from %s:%d (%s) for port %d.", + addr, addrport[1], fqdn, self.port) + sock.close() + except: + pass diff --git a/tools/python/xen/web/unix.py b/tools/python/xen/web/unix.py index 64ae2fcf1b..174e7284bc 100644 --- a/tools/python/xen/web/unix.py +++ b/tools/python/xen/web/unix.py @@ -21,15 +21,15 @@ import socket import os import os.path -from connection import * +import connection -class UnixListener(SocketListener): - - def __init__(self, path, protocol, backlog=None): - SocketListener.__init__(self, protocol, backlog=backlog) +class UnixListener(connection.SocketListener): + def __init__(self, path, protocol_class): self.path = path - + connection.SocketListener.__init__(self, protocol_class) + + def createSocket(self): pathdir = os.path.dirname(self.path) if not os.path.exists(pathdir): @@ -45,9 +45,6 @@ class UnixListener(SocketListener): sock.bind(self.path) return sock - def acceptConnection(self, sock, protocol, addr): - return SocketServerConnection(sock, protocol, self.path, self) - -def listenUNIX(path, protocol, backlog=None): - UnixListener(path, protocol, backlog=backlog).listen() + def acceptConnection(self, sock, _): + connection.SocketServerConnection(sock, self.protocol_class) diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py index b61532737a..c806f75e2f 100644 --- a/tools/python/xen/xend/XendRoot.py +++ b/tools/python/xen/xend/XendRoot.py @@ -75,6 +75,8 @@ class XendRoot: """Default port xend serves relocation at. """ xend_relocation_port_default = '8002' + xend_relocation_hosts_allow_default = '' + """Default for the flag indicating whether xend should run a unix-domain server.""" xend_unix_server_default = 'yes' @@ -194,6 +196,10 @@ class XendRoot: """ return self.get_config_int('xend-relocation-port', self.xend_relocation_port_default) + def get_xend_relocation_hosts_allow(self): + return self.get_config_value("xend-relocation-hosts-allow", + self.xend_relocation_hosts_allow_default) + def get_xend_address(self): """Get the address xend listens at for its HTTP port. This defaults to the empty string which allows all hosts to connect. diff --git a/tools/python/xen/xend/server/relocate.py b/tools/python/xen/xend/server/relocate.py index c20d577156..1b7ed157e9 100644 --- a/tools/python/xen/xend/server/relocate.py +++ b/tools/python/xen/xend/server/relocate.py @@ -16,6 +16,7 @@ # Copyright (C) 2005 XenSource Ltd #============================================================================ +import re import sys import StringIO @@ -116,8 +117,16 @@ def listenRelocation(): xroot = XendRoot.instance() if xroot.get_xend_unix_server(): path = '/var/lib/xend/relocation-socket' - unix.listenUNIX(path, RelocationProtocol) + unix.UnixListener(path, RelocationProtocol) if xroot.get_xend_relocation_server(): port = xroot.get_xend_relocation_port() interface = xroot.get_xend_relocation_address() - tcp.listenTCP(port, RelocationProtocol, interface=interface) + + hosts_allow = xroot.get_xend_relocation_hosts_allow() + if hosts_allow == '': + hosts_allow = None + else: + hosts_allow = map(re.compile, hosts_allow.split(" ")) + + tcp.TCPListener(RelocationProtocol, port, interface = interface, + hosts_allow = hosts_allow) -- 2.30.2